// static/main.js

const MODEL = 'llama3.2:1b';

// 维护一个“待上传”集合，包含 File 对象以及它的相对路径（相对于批次的顶层）
const queue = []; // { file: File, relPath: string }
const roots = new Set(); // 顶层根项（用于 commit 消息）

const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('file-input');
const dirInput = document.getElementById('dir-input');
const preview = document.getElementById('preview');
const uploadBtn = document.getElementById('upload-btn');
const progressEl = document.getElementById('progress');
const resultEl = document.getElementById('result');

function setProgress(percent) {
    const p = Math.max(0, Math.min(100, percent | 0));
    progressEl.setAttribute('data-percent', p);
    const bar = progressEl.querySelector('.bar');
    if (bar) bar.style.width = p + '%';
}

let progress = 0;
let timer;
function startPseudoProgress() {
    progress = 0;
    setProgress(progress);
    timer = setInterval(() => {
        if (progress < 70) {
            progress += 2;
        } else if (progress < 95) {
            progress += 0.2;
        } else {
            clearInterval(timer);
            return;
        }
        setProgress(progress);
    }, 100);
}

// 下载相关
function downloadResource(relPath) {
    // 直接跳转到后端提供的下载接口
    window.open(`/download?path=${encodeURIComponent(relPath)}`);
}

// 删除相关
function showDeleteConfirm(relPath, cb) {
    if (confirm(`确定要删除：${relPath}？`)) cb();
}

async function deleteResource(relPath) {
    setProgress(0);
    resultEl.style.display = 'none';

    startPseudoProgress();
    try {
        const resp = await fetch('/delete', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ path: relPath }),
        });
        const data = await resp.json();
        clearInterval(timer);
        setProgress(100);
        if (!data.ok) {
            resultEl.className = 'ui negative message';
            resultEl.style.display = 'block';
            resultEl.textContent = `删除失败：${data.error || '未知错误'}`;
            return;
        }
        resultEl.className = 'ui positive message';
        resultEl.style.display = 'block';
        resultEl.textContent = '删除成功。';
        setTimeout(() => location.reload(), 600);
    } catch (e) {
        clearInterval(timer);
        resultEl.className = 'ui negative message';
        resultEl.style.display = 'block';
        resultEl.textContent = `网络或服务错误：${e}`;
    }
}

function updatePreview() {
    preview.innerHTML = '';
    queue.forEach(item => {
        const div = document.createElement('div');
        div.className = 'item';
        div.innerHTML = `
      <i class="file outline icon"></i>
      <div class="content mono">${item.relPath}</div>
    `;
        preview.appendChild(div);
    });
}

// bind bottoms
// 资源列表按钮事件绑定
document.addEventListener('DOMContentLoaded', function () {
    document.querySelectorAll('.resource-download-btn').forEach(btn => {
        btn.addEventListener('click', function () {
            const rel = this.getAttribute('data-rel');
            downloadResource(rel);
        });
    });
    document.querySelectorAll('.resource-delete-btn').forEach(btn => {
        btn.addEventListener('click', function () {
            const rel = this.getAttribute('data-rel');
            showDeleteConfirm(rel, () => deleteResource(rel));
        });
    });
});

function addFileWithRelPath(file, relPath) {
    // 归一化路径展示
    const normalized = relPath.replace(/^\/+/, '');
    queue.push({ file, relPath: normalized });
    // 记录顶层根
    const top = normalized.split('/')[0];
    if (top) roots.add(top);
}

function traverseDataTransferItem(item, pathPrefix = '') {
    // 仅 chrome/edge 支持 webkitGetAsEntry
    const entry = item.webkitGetAsEntry ? item.webkitGetAsEntry() : null;
    if (!entry) return;

    if (entry.isFile) {
        entry.file(file => {
            addFileWithRelPath(file, pathPrefix + file.name);
            updatePreview();
        });
    } else if (entry.isDirectory) {
        const dirReader = entry.createReader();
        const readEntries = () => {
            dirReader.readEntries(entries => {
                if (!entries.length) return;
                entries.forEach(e => {
                    traverseDataTransferItem(
                        { webkitGetAsEntry: () => e },
                        pathPrefix + entry.name + '/'
                    );
                });
                readEntries();
            });
        };
        readEntries();
    }
}

dropzone.addEventListener('dragover', e => {
    e.preventDefault();
    dropzone.classList.add('dragover');
});
// eslint-disable-next-line no-unused-vars
dropzone.addEventListener('dragleave', e => {
    dropzone.classList.remove('dragover');
});
dropzone.addEventListener('drop', e => {
    e.preventDefault();
    dropzone.classList.remove('dragover');

    const items = e.dataTransfer.items;
    if (items && items.length) {
        for (const it of items) {
            if (it.kind === 'file') {
                // 支持文件或文件夹（目录）
                if (it.webkitGetAsEntry) {
                    traverseDataTransferItem(it, '');
                } else {
                    // 回退：无法遍历目录时，只能当普通文件
                    const file = it.getAsFile();
                    if (file) addFileWithRelPath(file, file.name);
                }
            }
        }
        updatePreview();
    } else {
        // 回退：某些浏览器仅提供 files
        const files = e.dataTransfer.files;
        for (const f of files) {
            const rel = f.webkitRelativePath || f.name;
            addFileWithRelPath(f, rel);
        }
        updatePreview();
    }
});

fileInput.addEventListener('change', e => {
    const files = e.target.files;
    for (const f of files) {
        const rel = f.name; // 纯文件，顶层就是文件名
        addFileWithRelPath(f, rel);
    }
    updatePreview();
    fileInput.value = '';
});

dirInput.addEventListener('change', e => {
    const files = e.target.files;
    for (const f of files) {
        const rel = f.webkitRelativePath || f.name;
        addFileWithRelPath(f, rel);
    }
    updatePreview();
    dirInput.value = '';
});

uploadBtn.addEventListener('click', async () => {
    if (queue.length === 0) {
        resultEl.className = 'ui warning message';
        resultEl.style.display = 'block';
        resultEl.textContent = '请先选择或拖拽文件/文件夹。';
        return;
    }

    const form = new FormData();
    queue.forEach(item => {
        form.append('files[]', item.file, item.file.name);
        form.append('paths[]', item.relPath);
    });
    // 记录本批次的顶层根项集合（用于分别 commit）
    Array.from(roots).forEach(r => form.append('batch_roots[]', r));

    setProgress(0);
    uploadBtn.classList.add('loading');
    resultEl.style.display = 'none';
    startPseudoProgress();

    try {
        const resp = await fetch('/upload', {
            method: 'POST',
            body: form,
        });
        const data = await resp.json();

        clearInterval(timer);
        setProgress(100); // 请求完成，直接100%
        uploadBtn.classList.remove('loading');

        if (!data.ok) {
            resultEl.className = 'ui negative message';
            resultEl.style.display = 'block';
            resultEl.textContent = `上传失败：${data.error || '未知错误'}`;
            return;
        }

        resultEl.className = 'ui positive message';
        resultEl.style.display = 'block';
        resultEl.textContent = '上传并提交成功。';
        // 清空上传队列
        queue.length = 0;
        roots.clear();
        updatePreview();

        // 动态添加新文件列表（无下载/删除按钮，仅有刷新按钮）
        const previewParent = document.getElementById('preview');
        const newList = document.createElement('div');
        newList.className = 'ui message';
        const filenames = form.getAll('paths[]');
        newList.innerHTML = `
            <div style="margin-bottom:8px;">新上传文件：</div>
            <div style="max-height:180px;overflow:auto;font-family:monospace;font-size:14px;line-height:1.7;">${filenames
                .map(f => `<div>${f}</div>`)
                .join('')}</div>
            <button id="refresh-btn-after-upload" class="ui blue button" style="margin-top:10px;">刷新页面以操作</button>
        `;
        previewParent.appendChild(newList);
        document.getElementById('refresh-btn-after-upload').onclick = () => location.reload();

        // === LLM分析文件名 ===
        if (filenames.length > 0) {
            showLLMToast(filenames);
        }
    } catch (e) {
        clearInterval(timer);
        uploadBtn.classList.remove('loading');
        resultEl.className = 'ui negative message';
        resultEl.style.display = 'block';
        resultEl.textContent = `网络或服务错误：${e}`;
    }
});

// Toast + LLM分析（非流式，带进度条）
function showLLMToast(filenames, opts = {}) {
    const model = opts.model || MODEL;
    const temperature = opts.temperature || 1;
    const api_key = opts.api_key || '';
    const prompt = `请用简洁、专业、友好的风格分析这些文件名的内容、用途、类型、潜在风险或亮点，并给出建议：\n${filenames
        .map(f => '- ' + f)
        .join('\n')}`;

    let toast;
    let lastResponse = '';
    // eslint-disable-next-line no-unused-vars
    let lastPrompt = prompt;
    let progress = 0;
    let progressTimer = null;
    let finished = false;

    // toast只显示纯文本，html标签转义
    function escapeHTML(str) {
        return str.replace(/[&<>"']/g, function (c) {
            return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
        });
    }

    // 进度条toast
    // eslint-disable-next-line no-unused-vars
    function showProgressToast() {
        // eslint-disable-next-line no-undef
        toast = Toastify({
            text: `<div style='min-width:220px;'>LLM分析中...<div style='margin-top:8px;width:100%;height:8px;background:#eee;border-radius:4px;overflow:hidden;'><div id='llm-toast-bar' style='height:8px;width:${progress}%;background:#2185d0;transition:width 0.2s;'></div></div></div>`,
            duration: 60000,
            gravity: 'top',
            position: 'right',
            close: true,
            escapeMarkup: false,
            onClick: function () {
                toast.hideToast();
                showDialog(lastResponse || '');
            },
        });
        toast.showToast();
    }

    function updateProgressBar(p) {
        progress = p;
        const bar = document.getElementById('llm-toast-bar');
        if (bar) bar.style.width = p + '%';
    }

    // eslint-disable-next-line no-unused-vars
    function startProgress() {
        progress = 0;
        let elapsed = 0;
        let interval = 100;
        let duration = 10000; // 10s
        let almostDone = false;
        progressTimer = setInterval(() => {
            if (finished) return;
            elapsed += interval;
            // 90%时间内线性前进，最后10%停住
            if (elapsed < duration * 0.9) {
                progress = Math.min(90, (elapsed / duration) * 100);
            } else {
                if (!almostDone) {
                    progress = 98;
                    almostDone = true;
                }
            }
            updateProgressBar(progress);
        }, interval);
    }

    function stopProgress() {
        finished = true;
        clearInterval(progressTimer);
        updateProgressBar(100);
        setTimeout(() => toast && toast.hideToast(), 500);
    }

    function showDialog(content) {
        // 无虚化、无阴影、无背景，仅白底边框
        const dialog = document.createElement('div');
        dialog.innerHTML = `
        <div style='max-width:520px;padding:16px;background:#fff;border:1px solid #bbb;border-radius:8px;box-shadow:none;position:fixed;top:18%;left:50%;transform:translate(-50%,0);z-index:99999;'>
            <div style='font-weight:bold;margin-bottom:6px;'>LLM分析</div>
            <div id='llm-dialog-content' style='margin-bottom:10px;white-space:pre-wrap;word-break:break-all;'>${escapeHTML(
                content
            )}</div>
            <textarea id='llm-reply-input' style='width:100%;height:60px;margin-bottom:8px;resize:vertical;' placeholder='输入你的追问或指令...'></textarea>
            <div style='display:flex;gap:8px;'>
                <button id='llm-reply-btn' style='flex:1;'>发送</button>
                <button id='llm-close-btn'>关闭</button>
            </div>
            <div style='margin-top:8px;font-size:12px;color:#888;'>模型: <input id='llm-model' value='${model}' style='width:110px;'> 温度: <input id='llm-temp' value='${temperature}' style='width:40px;'> API_KEY: <input id='llm-key' value='${api_key}' style='width:90px;'></div>
        </div>
        `;
        document.body.appendChild(dialog);
        // 发送按钮
        dialog.querySelector('#llm-reply-btn').onclick = async function () {
            const input = dialog.querySelector('#llm-reply-input').value.trim();
            if (!input) return;
            const m = dialog.querySelector('#llm-model').value || model;
            const t = parseFloat(dialog.querySelector('#llm-temp').value) || temperature;
            const k = dialog.querySelector('#llm-key').value || api_key;
            const replyBtn = dialog.querySelector('#llm-reply-btn');
            const contentEl = dialog.querySelector('#llm-dialog-content');
            replyBtn.disabled = true;
            replyBtn.textContent = '分析中...';
            contentEl.textContent = '';
            // 流式请求LLM
            // eslint-disable-next-line no-unused-vars
            let streamResult = '';
            await fetchLLMStream(input, m, t, k, lastResponse, contentEl, {
                update: function (txt) {
                    streamResult = txt;
                    contentEl.textContent = txt;
                },
            }).then(txt => {
                lastResponse = txt;
            });
            replyBtn.disabled = false;
            replyBtn.textContent = '发送';
            dialog.querySelector('#llm-reply-input').value = '';
        };
        // 关闭按钮
        dialog.querySelector('#llm-close-btn').onclick = function () {
            document.body.removeChild(dialog);
        };
    }

    // // 显示进度条toast（已禁用）
    // showProgressToast();
    // startProgress();

    // === 流式请求LLM ===
    // 1. 创建toast并提供update方法
    let streamText = '';
    // eslint-disable-next-line no-undef
    let streamToast = Toastify({
        text: `<div id='llm-stream-toast' style='min-width:220px;max-width:400px;white-space:pre-wrap;word-break:break-all;'>LLM分析中...</div>`,
        duration: 60000,
        gravity: 'top',
        position: 'right',
        close: true,
        escapeMarkup: false,
        onClick: function () {
            streamToast.hideToast();
            showDialog(streamText || '');
        },
    });
    streamToast.update = function (txt) {
        streamText = txt;
        const el = document.getElementById('llm-stream-toast');
        if (el) el.innerHTML = escapeHTML(txt || '');
    };
    streamToast.showToast();

    // 2. 启动流式fetch
    fetchLLMStream(prompt, model, temperature, api_key, null, null, streamToast).then(txt => {
        lastResponse = txt;
        stopProgress(); // 可选：结束进度条
        // 最终内容已在toast中更新，无需再新建toast
    });
}

// 非流式LLM请求
// eslint-disable-next-line no-unused-vars
async function fetchLLMNonStream(prompt, model, temperature, api_key, lastMsg, contentEl) {
    const body = {
        model: model || MODEL,
        prompt: prompt,
        options: { temperature: temperature || 1 },
    };
    if (lastMsg) {
        body.messages = [
            { role: 'system', content: '你是专业的文件分析助手。' },
            { role: 'assistant', content: lastMsg },
            { role: 'user', content: prompt },
        ];
    }
    const headers = { 'Content-Type': 'application/json' };
    if (api_key) headers['API-Key'] = api_key;
    let result = '';
    try {
        const resp = await fetch('http://10.115.80.197:5000/api/chat', {
            method: 'POST',
            headers,
            body: JSON.stringify(body),
        });
        const data = await resp.json();
        result =
            data.choices?.[0]?.message?.content ||
            data.message ||
            data.response ||
            JSON.stringify(data);
        if (contentEl) contentEl.textContent = result;
        return result;
    } catch (e) {
        result = 'LLM请求失败: ' + e;
        if (contentEl) contentEl.textContent = result;
        return result;
    }
}

// LLM流式请求（只创建一个toast并持续更新内容）
async function fetchLLMStream(
    prompt,
    model,
    temperature,
    api_key,
    lastMsg,
    contentEl,
    toastRef // 新增参数，传递toast对象的引用
) {
    const body = {
        model: model || MODEL,
        prompt: prompt,
        options: { temperature: temperature || 1 },
    };
    if (lastMsg) {
        body.messages = [
            { role: 'system', content: '你是专业的文件分析助手。' },
            { role: 'assistant', content: lastMsg },
            { role: 'user', content: prompt },
        ];
    }
    const headers = { 'Content-Type': 'application/json' };
    if (api_key) headers['API-Key'] = api_key;
    let result = '';
    try {
        const resp = await fetch('http://10.115.80.197:5000/api/chat/stream', {
            method: 'POST',
            headers,
            body: JSON.stringify(body),
        });
        if (!resp.body || !window.ReadableStream) {
            // fallback
            const data = await resp.json();
            result =
                data.choices?.[0]?.message?.content ||
                data.message ||
                data.response ||
                JSON.stringify(data);
            if (contentEl) contentEl.textContent = result;
            if (toastRef && toastRef.update) toastRef.update(result);
            return result;
        }
        const reader = resp.body.getReader();
        let decoder = new TextDecoder('utf-8');
        let done = false;
        let buffer = '';
        while (!done) {
            const { value, done: doneReading } = await reader.read();
            done = doneReading;
            if (value) {
                buffer += decoder.decode(value, { stream: true });
                let lines = buffer.split(/\r?\n/);
                buffer = lines.pop();
                for (let line of lines) {
                    if (line.startsWith('data:')) {
                        let data = line.slice(5).trim();
                        if (data === '[DONE]' || data === 'done') continue;
                        try {
                            let obj = JSON.parse(data);
                            let txt =
                                obj.message ||
                                obj.response ||
                                obj.choices?.[0]?.delta?.content ||
                                obj.choices?.[0]?.message?.content ||
                                '';
                            if (txt) {
                                result += txt;
                                if (contentEl) contentEl.textContent = result;
                                if (toastRef && toastRef.update) toastRef.update(result);
                            }
                            // eslint-disable-next-line no-unused-vars, no-empty
                        } catch (e) {}
                    }
                }
            }
        }
        if (contentEl) contentEl.textContent = result;
        if (toastRef && toastRef.update) toastRef.update(result);
        return result;
    } catch (e) {
        result = 'LLM请求失败: ' + e;
        if (contentEl) contentEl.textContent = result;
        if (toastRef && toastRef.update) toastRef.update(result);
        return result;
    }
}
